package com.augurit.smartform.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.augurit.common.dao.SysMetaColumnDao;
import com.augurit.common.dao.SysMetaTableDao;
import com.augurit.common.entity.SysMetaColumn;
import com.augurit.common.entity.SysMetaTable;
import com.augurit.common.sysmeta.convert.SysMetaColumnConvertor;
import com.augurit.common.sysmeta.web.form.SysMetaColumnForm;
import com.augurit.common.util.lang.StringUtils;
import com.augurit.smartform.converter.FieldConverter;
import com.augurit.smartform.converter.FormConverter;
import com.augurit.smartform.converter.PageConverter;
import com.augurit.smartform.dao.SmFunctionDao;
import com.augurit.smartform.dao.SmPageDao;
import com.augurit.smartform.dao.SmartFormDao;
import com.augurit.smartform.database.Column;
import com.augurit.smartform.database.DatabaseParser;
import com.augurit.smartform.database.SQLWrapper;
import com.augurit.smartform.database.Table;
import com.augurit.smartform.database.change.ColumnChangeInfo;
import com.augurit.smartform.database.change.ColumnModifyInfo;
import com.augurit.smartform.database.change.ColumnNameChange;
import com.augurit.smartform.database.change.CopyDataInfo;
import com.augurit.smartform.display.PageElement;
import com.augurit.smartform.display.TagElement;
import com.augurit.smartform.entity.SmFunction;
import com.augurit.smartform.entity.SmPage;
import com.augurit.smartform.service.ISmartFormService;
import com.augurit.smartform.util.XMLHelper;

@Service
@Transactional
public class SmartFormService implements ISmartFormService {
	@Autowired
	private SysMetaColumnDao sysMetaColumnDao;
	@Autowired
	private SysMetaTableDao sysMetaTableDao;
	@Autowired
	private SmPageDao smPageDao;
	@Autowired
	private SmFunctionDao smFunctionDao;
	@Autowired
	private SmartFormDao smartFormDao;
	@Autowired
	private DatabaseParser dbParser;
	
	/**
	 * 根据名称从数据库中查询最新的表单
	 * @param name
	 * @return
	 * cuigeqiang
	 */
	public SysMetaTable getLastedSmFormByName(String name){
		return sysMetaTableDao.getLastedSmFormByName(name);
	}
	
	/**
	 * 根据名称从数据库中查询所有版本的表单
	 * @param name
	 * @return
	 * cuigeqiang
	 */
	public List<SysMetaTable> getAllSmFormByName(String name){
		return sysMetaTableDao.getAllSmFormByName(name);
	}
	
	/**
	 * 删除所有版本的表单数据库结构
	 * @param name
	 * cuigeqiang
	 */
	public void deleteAllSmFormByName(String name){
		List<SysMetaTable> sysMetaTables=this.getAllSmFormByName(name);
		if(sysMetaTables!=null&&sysMetaTables.size()>0){
			for(SysMetaTable sysMetaTable : sysMetaTables){
				List<Table> tables=dbParser.parseToDescTables(sysMetaTable.getRawXml());
				for(Table table : tables){
					if(name.equalsIgnoreCase(table.getName())){
						this.executeDropAny(table);
					}
				}
			}
		}
	}
	
	/**
	 * 创建表、序列、约束和添加共用表记录
	 * @param table
	 * cuigeqiang
	 */
	public void executeCreateAny(Table table){
		if(table!=null){
			List<String> createAnySqls=SQLWrapper.createAny(table);
			smartFormDao.executeUpdateList(createAnySqls);
			
			SysMetaTable smForm=FormConverter.convertToSysMetaTable(table);
			sysMetaTableDao.save(smForm);
			
			List<SysMetaColumn> sysMetaColumnList=new ArrayList<SysMetaColumn>();
			List<Column> columns=table.getColumn();
			for(int i=0;i<columns.size();i++){
				Column column=columns.get(i);
				column.setTableId(smForm.getId());
				SysMetaColumn sysMetaColumn=FieldConverter.convertToSysMetaColumn(column);
				sysMetaColumnList.add(sysMetaColumn);
			}
			sysMetaColumnDao.saveSysMetaColumnList(sysMetaColumnList);
		}
	}
	
	/**
	 * 拷贝表数据和序列
	 * @param copyDataInfo
	 * cuigeqiang
	 */
	public void executeCopyData(CopyDataInfo copyDataInfo){
		if(copyDataInfo!=null){
			List<String> copyDataInfoSql=SQLWrapper.copyTableData(copyDataInfo);
			smartFormDao.executeUpdateList(copyDataInfoSql);
			
			List<String> copySeqenceSql=SQLWrapper.copySequence(copyDataInfo);
			smartFormDao.executeCopySequence(copySeqenceSql);
		}
	}
	
	/**
	 * 删除表、序列、约束和添加共用表记录
	 * @param table
	 * cuigeqiang
	 */
	public void executeDropAny(Table table){
		List<String> dropAnySqls=SQLWrapper.dropAny(table);
		smartFormDao.executeUpdateList(dropAnySqls);
		
		sysMetaColumnDao.deleteByTableName(table.getFullName());
		sysMetaTableDao.deleteByTableName(table.getFullName());
	}
	
	/**
	 * 给数据库表增加列
	 * @param columnChangeInfo
	 * cuigeqiang
	 */
	public void executeAddColumn(ColumnChangeInfo columnChangeInfo){
		if(columnChangeInfo!=null&&columnChangeInfo.getAddColumns()!=null&&columnChangeInfo.getAddColumns().size()>0){
			List<String> addColumnSqls=SQLWrapper.addColumn(columnChangeInfo);
			smartFormDao.executeUpdateList(addColumnSqls);
			
			SysMetaTable sysMetaTable=sysMetaTableDao.getLastedSmFormByTableName(columnChangeInfo.getNewTable().getFullName());
			
			List<SysMetaColumn> sysMetaColumnList=new ArrayList<SysMetaColumn>();
			List<Column> columns=columnChangeInfo.getAddColumns();
			for(int i=0;i<columns.size();i++){
				Column column=columns.get(i);
				column.setTableId(sysMetaTable.getId());
				SysMetaColumn sysMetaColumn=FieldConverter.convertToSysMetaColumn(column);
				sysMetaColumnList.add(sysMetaColumn);
			}
			sysMetaColumnDao.saveSysMetaColumnList(sysMetaColumnList);
		}
	}
	
	/**
	 * 删除数据库表列
	 * @param columnChangeInfo
	 * cuigeqiang
	 */
	public void executeDelColumn(ColumnChangeInfo columnChangeInfo){
		if(columnChangeInfo!=null&&columnChangeInfo.getDelColumns()!=null&&columnChangeInfo.getDelColumns().size()>0){
			List<String> delColumnSqls=SQLWrapper.delColumn(columnChangeInfo);
			smartFormDao.executeUpdateList(delColumnSqls);
			
			List<Column> columns=columnChangeInfo.getDelColumns();
			for(int i=0;i<columns.size();i++){
				Column column=columns.get(i);
				sysMetaColumnDao.deleteByFieldId(column.getFieldId());
			}
		}
	}
	
	/**
	 * 重命名数据库列
	 * @param columnChangeInfo
	 * cuigeqiang
	 */
	public void executeRenameColumn(ColumnChangeInfo columnChangeInfo){
		if(columnChangeInfo!=null&&columnChangeInfo.getModifyColumns()!=null&&columnChangeInfo.getModifyColumns().size()>0){
			List<String> renameColumnSqls=SQLWrapper.renameColumn(columnChangeInfo);
			smartFormDao.executeUpdateList(renameColumnSqls);
			
			this.updateSysMetaColumn(columnChangeInfo);
		}
	}
	
	/**
	 * 修改数据库列长度、精度、标度、默认值、是否为空、唯一键、索引等信息
	 * @param columnChangeInfo
	 * cuigeqiang
	 */
	public void executeModifyColumn(ColumnChangeInfo columnChangeInfo){
		if(columnChangeInfo!=null&&columnChangeInfo.getModifyColumns()!=null&&columnChangeInfo.getModifyColumns().size()>0){
			List<String> modifyColumnSqls=SQLWrapper.modifyColumn(columnChangeInfo);
			smartFormDao.executeUpdateList(modifyColumnSqls);
			
			this.updateSysMetaColumn(columnChangeInfo);
		}
	}
	
	/**
	 * 查询相同页面名称的数量
	 * @param name
	 * @return
	 * cuigeqiang
	 */
	public long countPagesByName(String name){
		return smPageDao.countByName(name);
	}
	
	/**
	 * 保存转换页面的相关数据
	 * @param page
	 * cuigeqiang
	 */
	public SmPage savePage(PageElement page){
		SmPage oldPage=smPageDao.getSmPageByPageCode(page.getPageCode());
		if(oldPage!=null){
			PageConverter.convertToSmPage(page, oldPage);
		}else{
			oldPage=PageConverter.convertToSmPage(page);
		}
			smPageDao.save(oldPage);
		List<SmFunction> functions=new ArrayList<SmFunction>();
		this.setFunctionsByPage(page, functions);
		this.setPageId(oldPage, functions);
		smFunctionDao.deleteByPageId(oldPage.getId());
		smFunctionDao.saveFunctions(functions);
		
		return oldPage;
	} 
	
	/**
	 * 根据ID找到JSP的路径
	 * @param pageId
	 * @return
	 * cuigeqiang
	 */
	public String getJspPath(String pageId){
		Long id=Long.parseLong(pageId);
		SmPage page=smPageDao.get(id);
		String path=page.getJspPath();
		return path;
	}
	
	/**
	 * 根据ID找到JSP的路径
	 * @param pageId
	 * @return
	 * cuigeqiang
	 */
	public String getJspPathByPageCode(String pageCode){
		SmPage page=smPageDao.getSmPageByPageCode(pageCode);
		String path=page.getJspPath();
		return path;
	}
	
	/**
	 * 查询数据库中保存的最新版本的XML文件
	 * @param table
	 * @return
	 * cuigeqiang
	 */
	public String getOldXml(Table table){
		String oldXml="";
		List<SysMetaTable> forms=sysMetaTableDao.getFormsByTable(table);
		if(forms!=null&&forms.size()>0){
			oldXml=forms.get(0).getRawXml();
		}
		return oldXml;
	}
	
	/**
	 * 得到所有版本的智能表单
	 * @return
	 * cuigeqiang
	 */
	public List<SysMetaTable> getAllLastedSmartForms(){
		List<SysMetaTable> forms=new ArrayList<SysMetaTable>();
		List<SysMetaTable> allForms=sysMetaTableDao.getAllSmartForms();
		Set<String> names=new HashSet<String>();
		for(SysMetaTable smForm : allForms){
			String upperName=smForm.getFormName().toUpperCase();
			if(!names.contains(upperName)){
				forms.add(smForm);
				names.add(upperName);
			}
		}
		return forms;
	}
	
	/**
	 * 通过FORMID得到所有字段
	 * @param formId
	 * @return
	 * cuigeqiang
	 */
	public List<Map> getAllFieldByFormId(String formIdStr){
		List<Map> fields=new ArrayList<Map>();
		List<Map> innerFields=null;
		if(StringUtils.isNotBlank(formIdStr)){
			Long formId=Long.parseLong(formIdStr);
			SysMetaTable sysMetaTable=sysMetaTableDao.get(formId);
			String fullTableName=sysMetaTable.getTableName();
			innerFields=sysMetaColumnDao.getFieldsByTableName(fullTableName);
		}
		if(innerFields!=null){
			fields=innerFields;
		}
		return fields;
	}
	
	/**
	 * 通过PAGECODE查询SMPAGE
	 * @param pageCode
	 * @return
	 * cuigeqiang
	 */
	public SmPage getSmPageByPageCode(String pageCode){
		return smPageDao.getSmPageByPageCode(pageCode);
	}
	
	/**
	 * 通过PAGEID查询SMPAGE
	 * @param pageId
	 * @return
	 * cuigeqiang
	 */
	public SmPage getSmPageByPageId(String pageId){
		return smPageDao.getSmPageByPageId(pageId);
	}
	
	/**
	 * 检查有字段变动时更新SysMetaTable
	 * @param columnChangeInfo
	 * cuigeqiang
	 */
	public void updateSysMetaTable(ColumnChangeInfo columnChangeInfo){
		if(columnChangeInfo!=null){
			SysMetaTable sysMetaTable=sysMetaTableDao.getLastedSmFormByTableName(columnChangeInfo.getNewTable().getFullName());
			FormConverter.convertToSysMetaTable(columnChangeInfo.getNewTable(),sysMetaTable);
			sysMetaTableDao.save(sysMetaTable);
		}
	}
	
	/**
	 * 根据ColumnChangeInfo更新SysMetaColumn
	 * @param columnChangeInfo
	 * cuigeqiang
	 */
	public void updateSysMetaColumn(ColumnChangeInfo columnChangeInfo){
		Map<String,ColumnModifyInfo> modifyColumns=columnChangeInfo.getModifyColumns();
		Iterator<ColumnModifyInfo> it=modifyColumns.values().iterator();
		while(it.hasNext()){
			ColumnModifyInfo columnModifyInfo=it.next();
			if(columnModifyInfo.getColumnNameChange()!=null||
					columnModifyInfo.getColumnLengthChange()!=null||
					columnModifyInfo.getColumnPrecisionChange()!=null||
					columnModifyInfo.getColumnScaleChange()!=null||
					columnModifyInfo.getDefaultValueChange()!=null||
					columnModifyInfo.getDictionaryChange()!=null||
					columnModifyInfo.getNotNullChange()!=null||
					columnModifyInfo.getIsIndexChange()!=null||
					columnModifyInfo.getIsUniqueChange()!=null||
					columnModifyInfo.getColumnCnNameChange()!=null){
				this.updateSysMetaColumn(columnModifyInfo.getNewColumn());
			}
		}
	}
	
	/**
	 * 找到当前发布的表单
	 * @param sourceXml
	 * @return
	 * cuigeqiang
	 */
	public Table getCurrentTable(String sourceXml){
		List<Table> deepTables=dbParser.parseToAscTables(sourceXml);
		
		return this.getCurrentTable(sourceXml, deepTables);
	}
	
	/**
	 * 找到当前发布的表单
	 * @param sourceXml
	 * @param deepTables
	 * @return
	 */
	public Table getCurrentTable(String sourceXml,List<Table> deepTables){
		Table currentTable=null;
		String currentFormName=this.getFormNameByXml(sourceXml);
		if(StringUtils.isNotBlank(currentFormName)&&deepTables.size()>1){
			for(Table table : deepTables){
				if(currentFormName.equalsIgnoreCase(table.getName())){
					currentTable=table;
					break;
				}
			}
		}
		if(currentTable==null){
			currentTable=deepTables.get(0);
		}
		
		return currentTable;
	}
	
	/**
	 * 通过页面设置后端JS功能
	 * @param page
	 * @param functions
	 * cuigeqiang
	 */
	private void setFunctionsByPage(PageElement page,List<SmFunction> functions){
		Map<String,TagElement> elements=page.getElements();
		Iterator it=elements.entrySet().iterator();
		while(it.hasNext()){
			Map.Entry entry=(Map.Entry)it.next();
			TagElement element=(TagElement)entry.getValue();
			this.setFunctionsByElement(element, functions);
		}
	}
	
	/**
	 * 通过控件设置后端JS功能
	 * @param element
	 * @param functions
	 * cuigeqiang
	 */
	private void setFunctionsByElement(TagElement element,List<SmFunction> functions){
		if(StringUtils.isNotBlank(element.getOnblur())){
			String funcCallStr=element.getOnblur();
			SmFunction function=this.getFunction(element, funcCallStr);
			function.setEvent("blur");
			functions.add(function);
		}
		if(StringUtils.isNotBlank(element.getOnchange())){
			String funcCallStr=element.getOnchange();
			SmFunction function=this.getFunction(element, funcCallStr);
			function.setEvent("change");
			functions.add(function);
		}
		if(StringUtils.isNotBlank(element.getOnclick())){
			String funcCallStr=element.getOnclick();
			SmFunction function=this.getFunction(element, funcCallStr);
			function.setEvent("click");
			functions.add(function);
		}
		if(StringUtils.isNotBlank(element.getOndblclick())){
			String funcCallStr=element.getOndblclick();
			SmFunction function=this.getFunction(element, funcCallStr);
			function.setEvent("dblclick");
			functions.add(function);
		}
		if(StringUtils.isNotBlank(element.getOnfocus())){
			String funcCallStr=element.getOnfocus();
			SmFunction function=this.getFunction(element, funcCallStr);
			function.setEvent("focus");
			functions.add(function);
		}
		if(StringUtils.isNotBlank(element.getOnkeydown())){
			String funcCallStr=element.getOnkeydown();
			SmFunction function=this.getFunction(element, funcCallStr);
			function.setEvent("keydown");
			functions.add(function);
		}
		if(StringUtils.isNotBlank(element.getOnkeypress())){
			String funcCallStr=element.getOnkeypress();
			SmFunction function=this.getFunction(element, funcCallStr);
			function.setEvent("keypress");
			functions.add(function);
		}
		if(StringUtils.isNotBlank(element.getOnkeyup())){
			String funcCallStr=element.getOnkeyup();
			SmFunction function=this.getFunction(element, funcCallStr);
			function.setEvent("keyup");
			functions.add(function);
		}
		if(StringUtils.isNotBlank(element.getOnmousedown())){
			String funcCallStr=element.getOnmousedown();
			SmFunction function=this.getFunction(element, funcCallStr);
			function.setEvent("mousedown");
			functions.add(function);
		}
		if(StringUtils.isNotBlank(element.getOnmousemove())){
			String funcCallStr=element.getOnmousemove();
			SmFunction function=this.getFunction(element, funcCallStr);
			function.setEvent("mousemove");
			functions.add(function);
		}
		if(StringUtils.isNotBlank(element.getOnmouseout())){
			String funcCallStr=element.getOnmouseout();
			SmFunction function=this.getFunction(element, funcCallStr);
			function.setEvent("mouseout");
			functions.add(function);
		}
		if(StringUtils.isNotBlank(element.getOnmouseover())){
			String funcCallStr=element.getOnmouseover();
			SmFunction function=this.getFunction(element, funcCallStr);
			function.setEvent("mouseover");
			functions.add(function);
		}
		if(StringUtils.isNotBlank(element.getOnmouseup())){
			String funcCallStr=element.getOnmouseup();
			SmFunction function=this.getFunction(element, funcCallStr);
			function.setEvent("mouseup");
			functions.add(function);
		}
		if(StringUtils.isNotBlank(element.getOnselect())){
			String funcCallStr=element.getOnselect();
			SmFunction function=this.getFunction(element, funcCallStr);
			function.setEvent("select");
			functions.add(function);
		}
	}
	
	/**
	 * 设置函数名和参数
	 * @param function
	 * @param functionCallStr
	 * cuigeqiang
	 */
	private SmFunction getFunction(TagElement element,String funcCallStr){
		SmFunction function=new SmFunction();
		function.setFieldId(element.getId());
		String functionName=this.getFunctionName(funcCallStr);
		function.setFunction(functionName);
//取消后端JS允许传参的功能
//		String argument=this.getArguments(funcCallStr);	
//		function.setArgument(argument);	
		return function;
	}
	
	/**
	 * 从字符串中获得函数名
	 * @param function
	 * @return
	 * cuigeqiang
	 */
	private String getFunctionName(String function){
		String functionName="";
		Pattern pattern = Pattern.compile("\\w+\\s*\\(");
		Matcher matcher=pattern.matcher(function);
		if(matcher.find()){
			functionName=matcher.group();
		}
		functionName=functionName.substring(0, functionName.length()-1).trim();
		return functionName;
	}
	
	/**
	 * 得到参数字符串
	 * @param function
	 * @return
	 * cuigeqiang
	 */
	private String getArguments(String function){
		String argument="";
		Pattern pattern = Pattern.compile("\\(.*\\)");
		Matcher matcher=pattern.matcher(function);
		if(matcher.find()){
			argument=matcher.group();
		}
		if(StringUtils.isNotBlank(argument)){
			argument=argument.substring(1, argument.length()-1).trim();
		}
		return argument;
	}
	
	/**
	 * 设置页面ID属性
	 * @param page
	 * @param functions
	 * cuigeqiang
	 */
	private void setPageId(SmPage page,List<SmFunction> functions){
		for(SmFunction function : functions){
			function.setPageId(page.getId());
		}
	}
	
	/**
	 * 更新SysMetaColumn
	 * @param column
	 * cuigeqiang
	 */
	private void updateSysMetaColumn(Column column){
		if(column!=null){
			SysMetaColumn sysMetaColumn=sysMetaColumnDao.getColumnByFieldId(column.getFieldId());
			FieldConverter.convertToSysMetaColumn(column, sysMetaColumn);
			sysMetaColumnDao.save(sysMetaColumn);
		}
	}

	/**
	 * 读取XML中的FORMNAME
	 * @param xml
	 * @return
	 * cuigeqiang
	 */
	private String getFormNameByXml(String xml){
		Document document=XMLHelper.getDocument(xml);
		Element objElement=(Element)document.node(0);
		return objElement.attributeValue("name");
	}
}
